package com.xtpt.disaster.controller;

import com.alibaba.fastjson.JSON;
import com.xtpt.disaster.bean.*;
import com.xtpt.disaster.common.JinCang.JinCangCmdBuilder;
import com.xtpt.disaster.common.PortalResult;
import com.xtpt.disaster.common.ShenTong.ShenTongCmdBuilder;
import com.xtpt.disaster.common.consts.*;
import com.xtpt.disaster.service.DBMysqlJobDetailService;
import com.xtpt.disaster.service.DBNodeInfoService;
import com.xtpt.disaster.service.JobDetailService;
import com.xtpt.disaster.service.TaskInfoManageService;
import com.xtpt.disaster.utils.*;
import io.swagger.annotations.Api;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;

@CrossOrigin
@RestController
@RequestMapping("/rest/task/")
@Api(tags = "金仓数据库备份删除")
public class DBActionController {

    @Autowired
    JobDetailService jobDetailService;

    @Autowired
    DBNodeInfoService dbNodeInfoService;

    @Autowired
    QuartzSendBack quartzSendBack;

    @Autowired
    TaskInfoManageService taskInfoManageService;

    @Autowired
    ServerPathUtil serverPathUtil;

    @Autowired
    DBMysqlJobDetailService dbMysqlJobDetailService;


    @PostMapping("/submit")
    public PortalResult submit(@RequestBody TaskInfoEx parameters) {

        if(!StringUtils.isEmpty(parameters.getOldJobName()) && StringUtils.isEmpty(parameters.getTaskId()))
        {
            // 修改任务时
            parameters.setTaskId(Long.parseLong(parameters.getOldJobName()));
//            return PortalResult.error("未传入taskID且oldJobName不为空，请核对参数！");
        }
        if(StringUtils.isEmpty(parameters.getTaskId()) && StringUtils.isEmpty(parameters.getOldJobName()))
        {
            // 新增任务时生成taskId
            parameters.setTaskId(IDGenerator.longid());
        }
        if(StringUtils.isEmpty(parameters.getTaskId()))
        {
            return PortalResult.error("taskID不能为空！");
        }
        TaskInfo taskInfo = new TaskInfo();
        // 参数复制到任务实体
        BeanUtils.copyProperties(parameters, taskInfo);
        Long dbId;
        // 判断任务类型
        TaskTypeEnum taskType=TaskTypeEnum.getObject(taskInfo.getTaskType());
        if(taskType==TaskTypeEnum.RECOVER)
        {
            Long jobId=taskInfo.getJobDetailId();
            JobDetail backupJobDetail = dbMysqlJobDetailService.selectByPrimaryKey(jobId);
            if(backupJobDetail==null)
            {
                return PortalResult.error("jobId不存在，任务创建失败！");
            }
            dbId=backupJobDetail.getDbId();
        }
        else
        {
            dbId = taskInfo.getDbId();
        }
        DbnodeInfo dbNodeInfo = dbNodeInfoService.selectByPrimaryKey(dbId);
        String dbType=null;
        if(dbNodeInfo!=null)
        {
            DBEnum dbEnum=DBEnum.getObject(dbNodeInfo.getNodeDbType());
            if(dbEnum!=null)
            {
                dbType=dbEnum.getName().toLowerCase();
            }
        }
        if(dbType==null || dbType.isEmpty())
        {
            return PortalResult.error("数据库类型有误，任务创建失败！");
        }
        // 保存任务回调所需参数
        Object obj;
        if(taskType==TaskTypeEnum.BACKUP)
        {
            obj = new ParametersDBBackup();
        }
        else if (taskType==TaskTypeEnum.RECOVER)
        {
            obj = new ParametersDBRecover();
        }
        else
        {
            return PortalResult.error("未选择任务类型（备份、恢复），任务创建失败！");
        }

        // 新建调度任务参数实体
        ParametersTask quartzInfo=new ParametersTask();
        // 将参数传递到调度任务实体
        BeanUtils.copyProperties(parameters, quartzInfo);
        // 标识任务状态为成功
        taskInfo.setTaskStatus(StatusConst.SUCCESS);
        // 先写入数据库，再提交到调度
        // 防止立即任务已执行但任务数据仍未写入任务表导致调度任务失败
        int count = taskInfoManageService.insertOrUpdateTaskInfo(taskInfo);
        if (count == 0) {
            return PortalResult.error("未成功新增或更新任务记录，任务创建失败！");
        }
        // 格式化回调地址
        String restUrl = String.format("/rest/%s/%s",dbType, taskType.name().toLowerCase(Locale.ROOT));
        // 保存任务回调地址
        String callbackUrl=serverPathUtil.generateCallbackUrl(restUrl);
        // 复制不同过程所需的参数
        BeanUtils.copyProperties(parameters, obj);
        // 标识任务状态，发送任务到调度
        boolean statusOK= quartzSendBack.taskRegister(quartzInfo,callbackUrl,obj);
        if(statusOK) {
            return PortalResult.ok();
        } else {
            // 更新任务状态为失败
            taskInfo.setTaskStatus(StatusConst.ERROR);
            taskInfoManageService.updateTaskInfoById(taskInfo);
            return PortalResult.error("创建计划任务失败！");
        }
    }

    /**
     * @Description: 接收代理客户端任务执行结果
     * @Author: hpc
     * @Date: 2021/12/27 下午 3:13
     * @param jobId: 结果所属作业ID
     * @param resultStr: 结果字符串本身
     * @return: com.xtpt.disaster.common.PortalResult
     **/
    @RequestMapping("/receiver/{jobId}")
    public PortalResult receiver(@PathVariable("jobId") Long jobId, @RequestBody String resultStr)
    {
        if(jobId!=null && !StringUtils.isEmpty(resultStr))
        {
            JobDetail jobDetail=jobDetailService.getById(jobId);
            if(jobDetail==null)
            {
                LogUtil.logger.error("jobId:"+jobId+" 不存在！");
                return PortalResult.error(jobId+" 不存在！");
            }
            try {
                ClientCmdExecResult result= JSON.parseObject(resultStr,ClientCmdExecResult.class);
                jobDetail.setJobResult(JSON.toJSONString(result.getExecCmdResult()));
                jobDetail.setJobEndTime(TimeUtil.dateMaker());
                if(!result.isStatus())
                {
                    LogUtil.logger.error(JSON.toJSONString(result.getErrorCmdList()));
                }
                String serverFilesPath = jobDetail.getServerPath();
                boolean transOK=true;
                if(serverFilesPath!=null)
                {
                    for (String file:serverFilesPath.split(",")) {
                        transOK=cn.hutool.core.io.file.PathUtil.exists(Paths.get(file),true);
                        if(!transOK)
                        {
                            LogUtil.logger.error("文件："+file+"，未传输到服务器！");
                            break;
                        }
                    }
                }
                if(transOK)
                {
                    jobDetail.setJobStatus(StatusConst.SUCCESS);
                }
                else
                {
                    jobDetail.setJobStatus(StatusConst.ERROR);
                }
            }
            catch (Exception ex){
                jobDetail.setJobStatus(StatusConst.ERROR);
                jobDetail.setJobResult(jobDetail.getJobResult()+"\r\nException:"+ex.getMessage());
                LogUtil.logger.error(ex.getMessage());
                ex.printStackTrace();
            }
            Integer update= jobDetailService.updateByPrimaryKeySelective(jobDetail);
            LogUtil.logger.info("更新"+update+"条数据记录！");
            if(jobDetail.getJobStatus().equals(StatusConst.SUCCESS))
            {
                return PortalResult.ok("成功更新"+update+"条数据记录！");
            }
            else if(jobDetail.getJobStatus().equals(StatusConst.ERROR))
            {
                return PortalResult.ok("失败！"+jobDetail.getJobResult());
            }else
            {
                return PortalResult.ok("RUNNING");
            }
        }
        LogUtil.logger.error("结果上报参数不完整！\njobId:"+jobId+"\nresult:"+resultStr);
        return PortalResult.error("结果上报参数不完整！");
    }
}
